package drds.plus.repository.mysql.execute_plan_to_sql;

import drds.plus.sql_process.abstract_syntax_tree.execute_plan.ExecutePlan;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.dml.IPut;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.MergeQuery;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Query;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SqlConvertor {

    public DataNodeIdToSqlsMapMergeInfo convert(Map<String, String> extraCmd, ExecutePlan executePlan, boolean bindval) {
        DataNodeIdToSqlsMapMergeInfo dataNodeIdToSqlsMapMergeInfo = new DataNodeIdToSqlsMapMergeInfo();

        Map<String/* query columnName */, Sqls> sqlsMap = new HashMap<String, Sqls>();
        dataNodeIdToSqlsMapMergeInfo.setDataNodeIdToSqlsMap(sqlsMap);
        if (executePlan instanceof MergeQuery) {
            MergeQuery mergeQuery = (MergeQuery) executePlan;
            List<ExecutePlan> executePlanList = mergeQuery.getExecutePlanList();
            if (executePlanList == null) {
                throw new IllegalArgumentException("should not be here");
            }
            for (ExecutePlan subExecutePlan : executePlanList) {
                processOnenoMergeExecutor(bindval, dataNodeIdToSqlsMapMergeInfo, subExecutePlan);
            }
            fillOtherValues(dataNodeIdToSqlsMapMergeInfo, mergeQuery);
        } else if (executePlan instanceof Query) {
            processOnenoMergeExecutor(bindval, dataNodeIdToSqlsMapMergeInfo, executePlan);
            fillOtherValues(dataNodeIdToSqlsMapMergeInfo, (Query) executePlan);
        } else if (executePlan instanceof IPut) {
            processOnenoMergeExecutor(bindval, dataNodeIdToSqlsMapMergeInfo, executePlan);
        }
        return dataNodeIdToSqlsMapMergeInfo;

    }

    private void fillOtherValues(DataNodeIdToSqlsMapMergeInfo dataNodeIdToSqlsMapMergeInfo, Query query) {
        dataNodeIdToSqlsMapMergeInfo.setItemList(query.getItemList());
        dataNodeIdToSqlsMapMergeInfo.setGroupByList(query.getGroupByList());
        dataNodeIdToSqlsMapMergeInfo.setLimitFrom(query.getLimitFrom());
        dataNodeIdToSqlsMapMergeInfo.setLimitTo(query.getLimitTo());
        dataNodeIdToSqlsMapMergeInfo.setOrderByList(query.getOrderByList());
    }

    /**
     * 因为原则上，目前简化版本的执行树只有一个merge，所以抽一个方法公用
     *
     * @param dataNodeIdToSqlsMapMergeInfo
     * @param executePlan
     */
    private void processOnenoMergeExecutor(boolean bindVal, DataNodeIdToSqlsMapMergeInfo dataNodeIdToSqlsMapMergeInfo, ExecutePlan executePlan) {
        if (executePlan instanceof MergeQuery) {
            throw new IllegalStateException("sub setWhereAndSetNeedBuild is sort , not supported yet .");
        }
        if (executePlan instanceof IPut) {
            // 写入相关
            String dataNodeId = executePlan.getDataNodeId();
            addSql(dataNodeIdToSqlsMapMergeInfo, dataNodeId, executePlan);
        } else if (executePlan instanceof Query) {
            String dataNodeId = executePlan.getDataNodeId();
            // setWhereAndSetNeedBuild or join
            addSql(dataNodeIdToSqlsMapMergeInfo, dataNodeId, executePlan);
        }
    }

    private void addSql(DataNodeIdToSqlsMapMergeInfo dataNodeIdToSqlsMapMergeInfo, String dataNodeId, ExecutePlan executePlan) {
        Map<String, Sqls> dataNodeIdToSqlsMap = dataNodeIdToSqlsMapMergeInfo.getDataNodeIdToSqlsMap();
        Sqls sqls = dataNodeIdToSqlsMap.get(dataNodeId);
        if (sqls == null) {
            sqls = new Sqls();
            dataNodeIdToSqlsMap.put(dataNodeId, sqls);
        }

        if (executePlan instanceof Query) {
            ((Query) executePlan).setTopQuery(true);
        }
        ExecutePlanVisitor executePlanVisitor = new ExecutePlanVisitor(executePlan, null, null, null, null, true);
        executePlan.accept(executePlanVisitor);
        Sql sql = new Sql();
        sql.setSql(executePlanVisitor.getString());
        sql.setIndexToSetParameterMethodAndArgsMap(executePlanVisitor.getOutPutIndexToSetParameterMethodAndArgsMap());
        sqls.getSqlList().add(sql);
    }

}
